using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;

namespace ProjectEuler.Core
{
    public class Problem45 :IProjectEulerProblem
    {
        private readonly IList<long> Triangles = new List<long>();
        private readonly IList<long> Hexagonals = new List<long>();
        private readonly IList<long> Pentagonals = new List<long>();

        protected long FindTriangle(int n)
        {
            for(long i = 143;i<300000;i++)
            {
                Triangles.Add(Triangle(i));
                Hexagonals.Add(Hexagonal(i));
                Pentagonals.Add(Pentagonal(i));
            }

            var matches1 = from t in Triangles
                          join h in Hexagonals on t equals h
                          select t;

            var matches2 = from m in matches1
                            join p in Pentagonals on m equals p
                            select m;

            if (matches2.Count() >= n)
            {
                return matches2.ToList()[n - 1];
            }
            return -1;
        }

        protected long Hexagonal(long n)
        {
            return n*((2*n) - 1);
        }

        protected long Pentagonal(long n)
        {
            return (n*((3*n) - 1))/2;
        }

        protected long Triangle(long n)
        {
            return (n*(n + 1))/2;
        }

        public int Number
        {
            get { return 45; }
        }

        public string Description
        {
            get { return "Find the next triangle number that is also pentagonal and hexagonal."; }
        }

        public string Answer
        {
            get { return FindTriangle(2).ToString(); }
        }
    }

    [TestFixture]
    public class Problem45Tests : Problem45
    {
        [Test]
        public void Then_the_given_indexes_should_match_up()
        {
            Assert.AreEqual(Triangle(285), 40755);
            Assert.AreEqual(Pentagonal(165), 40755);
            Assert.AreEqual(Hexagonal(143), 40755);
        }

        [Test]
        public void Then_the_first_match_should_be_40755()
        {
            Assert.AreEqual(40755, FindTriangle(1));
        }

        [Test]
        public void Then_the_second_match_shouldnt_be_negative_1()
        {
            Assert.AreNotEqual(-1, FindTriangle(2));
        }

    }
}